home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Archive / Graphics / QuickDraw GX / GX->PostScript Sample / GXToPostScript / I⁄O Utilities / ResDump.cp < prev   
Encoding:
Text File  |  2000-09-28  |  31.1 KB  |  1,154 lines  |  [TEXT/MPS ]

  1. /*
  2.      File:        ResDump.c
  3.  
  4.      Contains:    QuickDraw GX to PostScript conversion code.
  5.                          File contains routines for the PrintF type of transmission 
  6.                          of device codes contained in the resources.  These routines 
  7.                          will be alternate ways to get data into the stream buffers.
  8.  
  9.      Version:    Technology:    Quickdraw GX 1.1.x
  10.       
  11.      Copyright:    © 1990-1997 by Apple Computer, Inc., all rights reserved. 
  12. */
  13.  
  14. // allow multiple references to single label
  15. #define resumeLabel(exception)
  16.  
  17.  
  18. #include <MacMemory.h>
  19. #include <Errors.h>
  20. #include <Resources.h>
  21. #include <TextUtils.h>
  22. #include <StdArg.h>
  23. #include <String.h>
  24. #include <GXMath.h>
  25. #include "GXToPSBuildConfig.h"
  26. #include "GXtoPostScript.h"
  27. #include "GXExceptions.h"
  28. #include "RDUtil.h"
  29. #include "IOUtilities.h"
  30.  
  31.  
  32. //<FF>
  33. /*******************************************
  34.  
  35.     Function: RDFlushBuffer
  36.     
  37.     Flushes the RD buffer by sending the buffer data message
  38.     
  39.     rdMap:            the RD map, yes - this is the only exported routine
  40.                                 that does not take the parameter block.  Oh well,
  41.                                 what are you gonna do.
  42.     
  43. ********************************************/
  44. OSErr RDFlushBuffer(TRDMapHdl rdMap)
  45. {
  46.     OSErr        status;
  47.     
  48.     register TRDMapPtr pRDMap = *rdMap;
  49.             
  50.     if (pRDMap->buffPtr == 0)
  51.         return(noErr);
  52.     
  53.     HLock((Handle)rdMap);
  54.     status = (*rdMap)->psDevice->BufferData(&(pRDMap->buffer[0]), pRDMap->buffPtr, gxNoBufferOptions);        
  55.     pRDMap->buffPtr = 0;
  56.     
  57.     HUnlock((Handle)rdMap);
  58.     
  59.     ncheck(status);
  60.     return(status);
  61.     
  62. }//RDFlushBuffer
  63.  
  64. //<FF>
  65. /******************************************
  66.     Function: RDBufferData:
  67.     
  68.     Standard function for buffering Data for the resource dump utility (Not a public call)
  69.     
  70.     data:            Pointer to the data to buffer.
  71.     size:            Size of the data to buffer.
  72.     pRDMap:        A pointer to the resource dump map.
  73.     flags:        Resource Dump Utility flags.
  74.  
  75. ******************************************/
  76. OSErr RDBufferData(char *data, long size, TRDMapHdl hRDMap, TRDFlags rdFlags);
  77. OSErr RDBufferData(char *data, long size, TRDMapHdl hRDMap, TRDFlags rdFlags)
  78. {
  79.                         
  80.     OSErr                    status = noErr;
  81.     TRDMapPtr            pRDMap;
  82.     long                    copySize;                            // How much we can copy into buffer.
  83.     Ptr                        inBuff;                                // Pointer into the buffer.
  84.  
  85.     if (size > kRDBufferSize) {                    // Don't bother buffering something huge, send message instead.
  86.     
  87.         nrequire(status = RDFlushBuffer(hRDMap), failed_RDBuff);
  88.         status = (*hRDMap)->psDevice->BufferData(data, size, (rdFlags & eRDMakeHex));
  89.         ncheck(status);
  90.     
  91.     } else {
  92.     
  93.         while (size > 0) {                                    // put data into buffer
  94.         
  95.             pRDMap = *hRDMap;                                    // Dereference the handle, may have moved.
  96.             
  97.             inBuff = pRDMap->buffer + pRDMap->buffPtr;                // point into the buffer.
  98.             copySize = kRDBufferSize - pRDMap->buffPtr;
  99.             
  100.             if (copySize <= 0) {
  101.             
  102.                 status = RDFlushBuffer(hRDMap);
  103.                 nrequire(status, failed_RDBuff);
  104.                 
  105.             } else {                                // Copy what we can into the buffer.
  106.             
  107.                 if (size < copySize)
  108.                     copySize = size;
  109.         
  110.                 BlockMoveData(data, inBuff, copySize);        // used to be memcpy(inBuff, data, copySize);  Cam says this is faster
  111.                 
  112.                 size -= copySize;
  113.                 data += copySize;
  114.                 pRDMap->buffPtr += copySize;
  115.             
  116.             }//end if
  117.         
  118.         }//end while
  119.         
  120.     }//end if
  121.     
  122.  
  123. failed_RDBuff:
  124.     return(status);
  125.  
  126. }//RDBufferData
  127.  
  128.  
  129.  
  130. //<FF>
  131. /******************************************
  132.     Function: RDBufferByte:
  133.     
  134.     Standard function for buffering a single byte of data
  135.     
  136.     aByte:        The byte to buffer.
  137.     pRDMap:        A pointer to the resource dump map.
  138.     flags:        Resource Dump Utility flags.
  139.  
  140. ******************************************/
  141. OSErr RDBufferByte(  char aByte, TRDMapHdl hRDMap, TRDFlags rdFlags);
  142. OSErr RDBufferByte(  char aByte, TRDMapHdl hRDMap, TRDFlags rdFlags)
  143.     {
  144. #pragma unused (rdFlags)
  145.  
  146.         register OSErr                    status = noErr;
  147.         TRDMapPtr                                pMap;
  148.         
  149.         if ((*hRDMap)->buffPtr == kRDBufferSize) {
  150.         
  151.             nrequire(status = RDFlushBuffer(hRDMap), failed_Flush);
  152.         
  153.         }//end if
  154.         
  155.         pMap = *hRDMap;
  156.         pMap->buffer[pMap->buffPtr] = aByte;
  157.         ++(pMap->buffPtr);
  158.                         
  159. failed_Flush:
  160.         return(status);
  161.     
  162.     }//RDBufferByte
  163.  
  164.  
  165.  
  166.  
  167.  
  168. //<FF>
  169. /* 
  170. * converts only fractional part of a fixed number into decimal form.
  171. */
  172. short FixFract2Str(    Fixed srcNum, char *dstStr );
  173. short FixFract2Str(    Fixed srcNum, char *dstStr )
  174. {
  175.     long        dstNum;
  176.     long        shiftIndx;
  177.     short        wholeRound;
  178.     
  179.     UInt8     *scratchPtr1;
  180.     
  181.     #define    kDecPlaces    4
  182.     #define kMultiplier    10000          // = pow( 10, kDecPlaces )
  183.     
  184.     // we take the fractional part of the source number, add 1 and multiply by 10,000
  185.     // the number we get is guaranteed to fit in a short ( MAXSHORT == 65535 )
  186.     // we round the number ( for improved accuracy ) and then converted to a string.
  187.     // since the number is guaranteed to be five digits long ( we added 1 before multipling
  188.     // by 10,000) then all we have to do to get the “right” thing is to shift the string
  189.     // left by 1.
  190.     
  191.     dstNum = FixRound( FixMul( srcNum + ff(1) , ff( kMultiplier ) ) );
  192.     NumToString( dstNum, (unsigned char *) dstStr );
  193.     
  194.     // the first pass is to see if we rounded to an integer
  195.     
  196.     wholeRound = dstStr[ 1 ] - '1';
  197.     
  198.     // the second pass is to adjust the string lenght because of
  199.     // trailing zeroes
  200.     
  201.     shiftIndx = kDecPlaces;
  202.     scratchPtr1 = (UInt8 *) &dstStr[ kDecPlaces + 1 ];             // + 1 to step over the 1 -- or 2
  203.         
  204.     while( *scratchPtr1-- == '0' )
  205.         --shiftIndx;
  206.     
  207.     dstStr[ 0 ] = shiftIndx;
  208.  
  209.     return( wholeRound );
  210.     
  211. }//FixFract2Str
  212.  
  213. //<FF>
  214. /***********************************************
  215.  
  216.     Function: RDBufferFixedVal
  217.     Converts a fixed point number to text and buffers it.
  218.     
  219.     pMap:            pointer to the map.
  220.     paramVal:    The fixed value to dump.
  221.     
  222. ************************************************/
  223. OSErr RDBufferFixedVal( Fixed paramVal, TRDMapHdl hRDMap, TRDFlags rdFlags);
  224. OSErr RDBufferFixedVal( Fixed paramVal, TRDMapHdl hRDMap, TRDFlags rdFlags)
  225.     {
  226.         OSErr                            status;
  227.         register    long         intPart;
  228.         register    Fixed      fractPart;
  229.         char                             fractStr[ 8 ];
  230.         char                            tempString[ 8 ];
  231.         Boolean                        wasNegative = false;
  232.         short                            roundUp;
  233.                 
  234.         intPart = (*(short*)(¶mVal));                                //get the whole number.
  235.  
  236.         if (paramVal < 0) {
  237.         
  238.             wasNegative = true;
  239.             paramVal = -paramVal;                        // This will negate the fractional part properly.
  240.             if (paramVal & 0x0000FFFF)            // If there was a fractional part:
  241.                 ++intPart;        // Add one to whole # because the fractional is always + and added to whole #.
  242.             
  243.         }//end if
  244.  
  245.         fractPart = paramVal & 0x0000FFFF;                            //Get the fraction as a fixed point number.
  246.             
  247.  
  248.         
  249.         if (fractPart != 0) {
  250.         
  251.             roundUp = FixFract2Str(fractPart, fractStr);            // Get the fract string, add any round up to int part.
  252.             if (wasNegative)
  253.                 intPart -= roundUp;
  254.             else
  255.                 intPart += roundUp;
  256.                 
  257.         } else {
  258.         
  259.             fractStr[ 0 ] = 0;
  260.             
  261.         }//end if
  262.             
  263.  
  264.         /** Make sure we dump the negative sign if the int part was zero **/
  265.         if (wasNegative && (intPart == 0)) {
  266.         
  267.             tempString[0] = 1;
  268.             tempString[1] = '-';
  269.             
  270.         } else {
  271.         
  272.             NumToString(intPart, (unsigned char *) tempString);
  273.             
  274.         }//end if
  275.  
  276.         
  277.         if (fractStr[ 0 ] != 0) {
  278.         
  279.             tempString[StrLength((unsigned char*)tempString) + 1] = '.';                    //stick the decimal point in.
  280.             tempString[0] += 1;                                                                                                        //update the length.
  281.         
  282.         } else if (intPart == 0) {                                                        // Make sure we have a zero string
  283.         
  284.             tempString[0] = 1;
  285.             tempString[1] = '0';
  286.             
  287.         }//end if
  288.         
  289.         
  290.         status = RDBufferData(&(tempString[1]), StrLength((unsigned char*)tempString), hRDMap, rdFlags);    //dump it.
  291.         nrequire(status, failed_Buff);
  292.         
  293.         //Dump the fractional part as a decimal.
  294.         
  295.         if (fractStr[ 0 ] != 0)
  296.             status = RDBufferData(&(fractStr[2]), StrLength((unsigned char*)fractStr), hRDMap, rdFlags);        //Blow it out.
  297.             
  298.  
  299. failed_Buff:
  300.  
  301.         return(status);
  302.  
  303.     }// RDBufferFixedVal
  304.                             
  305.  
  306.  
  307.  
  308.  
  309. //<FF>
  310. /**************************************
  311.     Routine: RDBufferSubstituteString
  312.     
  313.     Dumps a %s string parameter, substituting
  314.     characters as indicated by the call to
  315.     RDSetSubstitutions.
  316.     
  317.     string:                Pointer to the string to dump.
  318.     length:                How many characters in the string.
  319.     pRDMap:                pointer to the map record.
  320.     rdFlags:    The buffer flags to use.
  321.     
  322. ***************************************/
  323. OSErr RDBufferSubstituteString(Ptr string, long length, TRDMapHdl hRDMap, TRDFlags rdFlags);
  324. OSErr RDBufferSubstituteString(Ptr string, long length, TRDMapHdl hRDMap, TRDFlags rdFlags)
  325.     {
  326.         OSErr                    status = noErr;
  327.         TRDMapPtr            pRDMap;
  328.         long                    blockLen;                            //length of a block to dump.
  329.         Ptr                        beginBlock;                        //beginning of a block to dump.
  330.         Ptr                        inString;
  331.         Ptr                        endString;
  332.         long                    index;                                //index of character.
  333.         Handle                hSubst;                                //Substitution array handle.
  334.         Ptr                        pSubst;                                //dereference it.
  335.         Boolean                mustSubst;                        //should we substitute?
  336.         short                    nSubs;                                //How many substitutions are there?
  337.         short                    iSub;                                    //substitution index.
  338.         unsigned long    theChar;
  339.         
  340.         
  341.         pRDMap = *hRDMap;
  342.         nSubs = pRDMap->nSubs;
  343.         hSubst = pRDMap->hCharSubstitute;
  344.         HLockHi(hSubst);                                            //Must be locked becuase we call RDBufferData on it.
  345.             
  346.         endString = string + length;
  347.         beginBlock = string;
  348.         index = 0;
  349.         
  350.         
  351.         /***********
  352.             Buffer the string, using substitution:
  353.                 Build blocks that end, either at a character that must
  354.                 be substituted or at the end of the string,
  355.                 Dump the block, and the block ended at a substitution,
  356.                 Dump the substitution string.
  357.         ***********/
  358.         
  359.         while ( index < length ) {
  360.             
  361.             inString = beginBlock;
  362.             blockLen = 0;
  363.         
  364.             /** Build up a block of characters needing no substitution **/
  365.             mustSubst = false;
  366.             while ( (inString < endString) && !mustSubst) {
  367.             
  368.                 /*** Check the current character against substitution array. ***/
  369.                 
  370.                 //First do quick elimination against substitution bit array.
  371.                 // use hRDMap instead of pRDMap cause buffering can move memory.
  372.                 
  373.                 theChar = (unsigned long)*(unsigned char *)inString;
  374.                 mustSubst = BITTST((*hRDMap)->subsBits, theChar) != 0;
  375.                 
  376.                 // if we failed the bit test, find out which character in the substitution list.                    
  377.                 if (mustSubst) {
  378.                                     
  379.                     pSubst = *hSubst;        //point into the substitution array.
  380.                     
  381.                     for (iSub = nSubs-1; iSub >= 0; --iSub) {
  382.  
  383.                         if (*inString != *pSubst++)                        // the ++ moves past substitution char to pstring.
  384.                             pSubst += *(UInt8*)pSubst + 1;            //get to next substitution by adding length + 1
  385.                         else
  386.                             break;                                                            //If we found it, force exit of loop.
  387.                             
  388.                     }//end for
  389.                     
  390.                 } else {                //update the pointers if we are still in a block.
  391.                 
  392.                     ++blockLen;
  393.                     ++inString;
  394.                     
  395.                 }//end if
  396.                                 
  397.             }//end while
  398.             
  399.             //If we have a block, blow it out.
  400.             if (blockLen > 0) {
  401.             
  402.                 status = RDBufferData(beginBlock, blockLen, hRDMap, rdFlags);
  403.                 nrequire(status, failed_buff);
  404.                 
  405.             }//end if
  406.             
  407.             /******
  408.                 If we stopped at a substitution, substitute the character!
  409.                 The pSubst pointer is now pointing to the pascal string we should 
  410.                 substitute with, so dump it.
  411.             *******/
  412.             if (mustSubst) {
  413.             
  414.                 status = RDBufferData(&(pSubst[1]), (UInt8)pSubst[0], hRDMap, rdFlags);
  415.                 nrequire(status, failed_buff);
  416.                 
  417.             }//end if
  418.                 
  419.             beginBlock += blockLen + 1;
  420.             index += blockLen + 1;
  421.         
  422.         }//end while
  423.         
  424. failed_buff:
  425.  
  426.         HUnlock(hSubst);
  427.  
  428.         return(status);
  429.     
  430.     }//RDBufferSubstituteString
  431.  
  432. //<FF>
  433. /*********************************
  434.     Routine RDGetIndPstring:
  435.     
  436.     Finds the offset of an Indexed pstring element in the resource.
  437.     
  438.     hResource:            the resource to dissect.
  439.     index:                    the index of the desired element.
  440.     offset:                    The byte offset into the resource for that element.
  441.     
  442. **********************************/
  443. OSErr RDGetIndPstring(Handle hResource, short index, long *offset);
  444. OSErr RDGetIndPstring(Handle hResource, short index, long *offset)
  445.     {        
  446.         register long            byteCount;        //byte count into resource.
  447.         register char            *pByte;                //pointer into the resource.
  448.         register short        i;                        //loop counter.
  449.         register long            j;                        //internal offset
  450.         
  451.         pByte = *hResource;                        //Point to the beginning of the resource which
  452.                                                                     //    should contain the number of elements in the array.
  453.         
  454.  
  455.         require( ( index <= *(short*)(pByte) ) , failed_indexTooBig);
  456.                         
  457.         /** Find the offset **/
  458.         
  459.         j = sizeof(short);
  460.         pByte += sizeof(short);                                        //skip past the string count.
  461.         
  462.         for (i = 0; i < index; i++) {                            //Loop through the strings to get the offset.
  463.         
  464.             byteCount = 1 + *(UInt8*)pByte;                    //Get the length of the next string.
  465.             j += byteCount;                                                    //add the length to the offset.
  466.             pByte += byteCount;                                            //update the pointer.
  467.             
  468.         }//end for            
  469.         
  470.         *offset = j;
  471.         
  472.         return(noErr);
  473.         
  474. failed_indexTooBig:        
  475.         return(resNotFound);
  476.         
  477.     }//RDGetIndPstring
  478.  
  479. //<FF>
  480. /******************************************************************
  481.     Function:        RDGetResource:
  482.     
  483.     Called from RDResPrintf to get the resource containing the string to parse.
  484.     The resource is either obtained from the cache hanging off of the map
  485.     or from FetchResource.
  486.     
  487.     pRDMap:            Pointer to the RDMap record.
  488.     params:            the parameter block.
  489.     h:                    returned handle for resource.
  490.     
  491. *******************************************************************/
  492. OSErr    RDGetResource(TRDMapHdl hRDMap, TRDParams *params, Handle *h);
  493. OSErr    RDGetResource(TRDMapHdl hRDMap, TRDParams *params, Handle *h)
  494.     {
  495.         OSErr                        status;
  496.         // short                        currResRef;                        //refnum for current resource file.
  497.         Handle                    hResource;
  498.         TRDMapPtr                pRDMap;
  499.         
  500.         
  501.         // currResRef = CurResFile();
  502.         
  503.         pRDMap = *hRDMap;
  504.  
  505.         hResource = pRDMap->hLastResource;
  506.         if ((hResource == nil) || (params->resType != pRDMap->lastResType) 
  507.                                                      || (params->resID !=   pRDMap->lastResID) ) {
  508.             
  509.             hResource = GetResource(params->resType, params->resID);
  510.             nrequire(status = ResError(), failed_GetRes);
  511.             
  512.             pRDMap = *hRDMap;            // Get it again, getresource could have moved stuff.
  513.             
  514.             pRDMap->hLastResource = hResource;
  515.             pRDMap->lastResID = params->resID;
  516.             pRDMap->lastResType = params->resType;
  517.             // pRDMap->lastResRef = currResRef;
  518.             
  519.             //flag invalid offset and index.
  520.             
  521.             pRDMap->lastOffset = -1;
  522.             pRDMap->lastResIndex = -1;
  523.             
  524.         } else {
  525.         
  526.             if (*hResource == nil)
  527.                 LoadResource(hResource);
  528.                 
  529.             status = ResError();
  530.             nrequire (status, failed_GetRes);        
  531.         
  532.         }//end if
  533.         
  534.         *h = hResource;
  535.  
  536. failed_GetRes:
  537.  
  538.         return(status);
  539.     
  540.     }//RDGetResource
  541.  
  542.  
  543.  
  544.  
  545.  
  546. //<FF>
  547. /******************************************************************
  548.  
  549.                 PUBLIC ROUTINES
  550.                 
  551. *******************************************************************/
  552.  
  553. /***********************************************
  554.     Routine RDInit:
  555.     
  556.     This routine is used Initialize the Resource Dump Utility for a client.
  557.     
  558.     rdMap:                A map is allocated and returned to the client, client passes to other routines.
  559.                 
  560. *************************************************/
  561. OSErr RDInit(CGXtoPostScriptDevice* psDevice, TRDMapHdl *rdMap)
  562.     {
  563.         OSErr                    status;
  564.         TRDMapPtr            pRDMap;
  565.         
  566.         // Allocate the memory for the map
  567.         status = PrNewHandleClear((Handle*)rdMap, sizeof(TRDMapRec));
  568.         
  569.         nrequire(status, failed_AllMap);
  570.  
  571.         pRDMap = *(TRDMapHdl)*rdMap;
  572.         
  573.         pRDMap->xySep = 0x20;                                            //the default seperator is a space.
  574.         pRDMap->psDevice = psDevice;                            // Use this for calling BufferData.
  575.  
  576.     /**********************
  577.             
  578.             These taken care of by PrNewHandleClear
  579.             
  580.         pRDMap->nSubs = 0;
  581.         pRDMap->hCharSubstitute = nil;
  582.         pRDMap->hLastResource = nil;
  583.         pRDMap->lastResID = nil;
  584.         pRDMap->buffPtr = 0;
  585.         
  586.     ***********************/
  587.         
  588.  
  589. failed_AllMap:
  590.         
  591.         return(status);    
  592.     
  593.     }//RDInit
  594.  
  595.  
  596. //<FF>
  597. /***********************************************
  598.     Routine RDShutdown:
  599.     
  600.     This routine is used shut down the Dump Utility for a client.
  601.     
  602.     rdMap:                The resource dump map identifying the client.
  603.                 
  604. *************************************************/
  605. OSErr RDShutdown(TRDMapHdl rdMap)
  606.     {
  607.         Handle h;
  608.         OSErr     status;
  609.         
  610.         status = RDFlushBuffer(rdMap);
  611.         
  612.         h = (*rdMap)->hCharSubstitute;
  613.         DisposeHandle(h);
  614.         DisposeHandle((Handle)rdMap);
  615.         
  616.         return(status);
  617.     
  618.     }//RDShutdown
  619.  
  620. //<FF>
  621.  
  622.  
  623. /***********************************************
  624.     Routine RDResBDump:
  625.     
  626.     This routine is used to dump binary data from a wstring resource.
  627.     
  628.         params:                RD Parameter block.        
  629. *************************************************/
  630. OSErr RDResBDump(TRDParams *params)
  631.     {
  632.         TRDMapHdl                hMap;                                //handle to the map.
  633.         OSErr                        status;                            //error status.
  634.         Handle                    hResource;                    //Handle to the resource.
  635.         unsigned short    size;                                //How big is the data?
  636.         SInt8                        flags;                            //Handle flags.
  637.         
  638.         check(params);
  639.         
  640.         /*** Try to get the resource. ***/        
  641.         status = FetchResource(params->resType, params->resID, &hResource);
  642.         nrequire(status, failed_GetRes);
  643.                 
  644.         /** Lock the resource **/
  645.         flags = HGetState(hResource);
  646.         HLock(hResource);
  647.         
  648.         size = *(unsigned short*)(*hResource);        //Get the length from the first 2 bytes.
  649.         
  650.         hMap = (params->rdMap);
  651.         status = (*hMap)->psDevice->BufferData(*hResource + sizeof(short), size, (params->rdFlags & eRDMakeHex));        
  652.         nrequire(status, failed_Buffer);
  653.                 
  654.         HSetState(hResource, flags);
  655.         
  656. failed_Buffer:
  657. failed_GetRes:
  658.         return(status);
  659.     
  660.     }//RDResBDump
  661.  
  662.  
  663. //<FF>
  664. /**************************************
  665.     Routine RDResStrListDump
  666.     
  667.         Used to dump all strings in an indexed pstring
  668.         resource.
  669.         
  670.         params:                RD Parameter block.        
  671.         termString:        Terminator string (pascal string) for each string in the resource.
  672.                                         If nil, no character will be output.
  673.  
  674. ****************************************/
  675. OSErr RDResStrListDump(TRDParams *params, char *termString)
  676.     {
  677.         OSErr                        status = noErr;                //error status
  678.         Handle                    hResource;                        //handle for the resource.
  679.         TRDMapHdl                hMap;
  680.         short                        nString;                            //Number of strings in resource.
  681.         short                        i;                                        //loop counter.
  682.         char*                        pByte;                                //pointer into resource.
  683.         long                        byteCount;
  684.         SInt8                        flags;
  685.  
  686.         status = FetchResource(params->resType, params->resID, &hResource);
  687.         nrequire(status, failed_GetRes);
  688.         
  689.         
  690.         /** Lock the resource **/
  691.         flags = HGetState(hResource);
  692.         HLock(hResource);
  693.         
  694.         hMap = (params->rdMap);
  695.         
  696.         pByte = *hResource;
  697.         
  698.         nString = *(short*)(pByte);                                    // Get the number of strings.
  699.                 
  700.         /** Find the offset **/
  701.         pByte += sizeof(short);                                            //skip past the string count.
  702.         
  703.         for (i = nString - 1; i >= 0; --i) {                //Loop through strings and dump em.
  704.         
  705.             byteCount = *(UInt8*)pByte++;                            //Get the length of the next string.
  706.             
  707.             status = RDBufferData(pByte, byteCount, hMap, params->rdFlags);
  708.             nrequire(status, failed_buff);
  709.     
  710.             //Output the termination character after each string.
  711.             
  712.             if (termString != nil) {
  713.             
  714.                 status = RDBufferData(&(termString[1]), StrLength((unsigned char*)termString), hMap, params->rdFlags);                
  715.                 nrequire(status, failed_buff);
  716.                 
  717.             }//end if
  718.             
  719.             pByte += byteCount;                                            //update the pointer.
  720.             
  721.         }//end for            
  722.         
  723.         status = RDFlushBuffer(params->rdMap);
  724.         ncheck(status);
  725.  
  726. failed_buff:
  727.  
  728.         HSetState(hResource, flags);
  729.  
  730. failed_GetRes:
  731.         return(status);
  732.     
  733.     }//RDResStrListDump
  734.  
  735.  
  736. //<FF>
  737. /*********************************
  738.     Routine RDResPrintf:
  739.     
  740.         Used to dump a resource that requires parameter substitution.
  741.         Will work for those that don't have parameters also.
  742.         
  743.         The resources are Printf type strings:
  744.         
  745.             %d will substitute for an integer.
  746.             
  747.             %s will substitute for a string.  (actually 2 parameters must be passed for
  748.                      each %s - the first is the pointer to the string, the second is the length.
  749.                      
  750.             %h will substitute for hex data.  (actually 2 parameters must be passed for
  751.                      each %h - the first is the pointer to the data, the second is the length.
  752.  
  753.             %f will substitute for a fixed point number (buffered in floating point format).
  754.             
  755.             %p will substitute a fixed point point, using the map's seperation character between
  756.                     X and Y.
  757.             
  758.             %q will substitute a Pascal string.  Same substitutions as for %s.
  759.             
  760.             %b will substitute a Boolean with "T" or "F".  (note, for PostScript clients, you must define /T to be true and /F to be false
  761.                         before using this substitution.
  762.             
  763.             The Backslash (\) character is used for quoting, so if you want to output a % character
  764.                 use \% (Although a % that is not followed by a parameter specification will simply be
  765.                 output, too.
  766.             
  767.         
  768.         params:                RD parameter block.
  769.         resIndex:            Index of the string within the resource.
  770.         ...                        The parameters to substitute in the string resource.
  771.         
  772. ***********************************/
  773. OSErr RDResPrintf(TRDParams *params, ...)
  774.     {
  775.         TRDMapHdl                hRDMap;
  776.         TRDMapPtr                pRDMap;
  777.         OSErr                        status;                                //error status.
  778.         Handle                    hResource;                        //Handle for the resource.
  779.         long                        offset;                                //Offset into the resource.
  780.         short                        strLen;                                //length of the particular string.
  781.         short                        blockLen;                            //length of a string block.
  782.         char                        *rString;                            //The string from the resource to dump.
  783.         char                        *endOfString;                    //Address of the end of the string
  784.         char                        *inString;                        //next character in string.
  785.         char                        *beginBlock;                    //Beginning of a block to pass.
  786.                 
  787.         va_list                    paramPtr;                            //Pointer to next paramter.
  788.         long                        paramVal;                            //parameter value.
  789.         
  790.         SInt8                        flags;
  791.         
  792.         char                        tempString[12];                //for NumToString, a long can't be more than 10 digits.
  793.                                                                                     // plus one for length byte and another for the sign.
  794.         Boolean                    mustSubstitute;
  795.  
  796.         
  797.         status = noErr;
  798.         
  799.         hRDMap = (params->rdMap);
  800.         pRDMap = *hRDMap;
  801.         
  802.         mustSubstitute =  ((params->rdFlags & eRDCharSubs) != 0) && (pRDMap->nSubs > 0);
  803.         
  804.         /** Set up for variable parameter list **/
  805.         va_start(paramPtr, params);
  806.     
  807.         /*** Try to get the resource. ***/    
  808.         status = RDGetResource(hRDMap, params, &hResource);
  809.         nrequire (status, failed_GetRes);
  810.         
  811.         /** Lock the resource **/
  812.         flags = HGetState(hResource);
  813.         HLock(hResource);
  814.         
  815.         
  816.         pRDMap = *hRDMap;            // Grab pointer to map again, RDGetResource could have moved memory.
  817.         
  818.         //Get the offset of the element of the resource desired (either from cache or search for it).
  819.  
  820.         if (pRDMap->lastResIndex == params->resIndex) {
  821.         
  822.             offset = pRDMap->lastOffset;
  823.             
  824.         } else {
  825.         
  826.             status = RDGetIndPstring(hResource, params->resIndex, &offset);
  827.             nrequire(status, failed_GetInd);
  828.             
  829.             pRDMap->lastOffset = offset;
  830.             pRDMap->lastResIndex = params->resIndex;
  831.             
  832.         }//end if
  833.                 
  834.         //Now that we know where, get the pascal string out of the resource.
  835.         rString = (char*)(*(unsigned long*)hResource + offset);
  836.                 
  837.         //Prepare to parse for parameters.
  838.         strLen = (UInt8)(rString[0]);
  839.         inString = rString + 1;
  840.         endOfString = inString + strLen - 1;
  841.         
  842.         /****
  843.             Parse it:  Build blocks of the string to send out.  A block ends at a parameter
  844.                 Substitution or the end of the string.
  845.                 The substitutions themselves are also dumped as blocks.
  846.         ****/
  847.         
  848.         while (inString <= endOfString) {
  849.         
  850.             blockLen = 0;
  851.             beginBlock = inString;                        //beginning of next string block to dump.
  852.             
  853.             /** Build the next block of characters that need no parsing **/
  854.             while ((*inString != '%') && (*inString != '\\') && (inString <= endOfString)) {
  855.             
  856.                 ++blockLen;
  857.                 ++inString;
  858.                 
  859.             }//end while
  860.                         
  861.             /*** Blow out the current block. ****/
  862.             
  863.             if (blockLen > 0) {
  864.             
  865.                 status = RDBufferData(beginBlock, blockLen, hRDMap, params->rdFlags);
  866.                 nrequire (status, failed_buffering1);
  867.                 
  868.             }//end if
  869.             
  870.             if (inString <= endOfString) {                //must have stopped because of parsable character.
  871.             
  872.                 /*****************
  873.                     Parse the character we stopped on
  874.                 ******************/
  875.                 
  876.                 if (*inString == '\\') {                        // If we hit the quote character, output the next byte
  877.                 
  878.                     status = RDBufferByte(*(++inString), hRDMap, params->rdFlags);
  879.                     ++inString;                                                                                                        //Get ready for next block.
  880.                                     
  881.                 } else    {        //If we stopped before end of string then we must be at a '%' so parse parameters.
  882.                 
  883.                     ++inString;                //skip to the character after where we stopped so we can parse next block.
  884.     
  885.                     switch(*inString++) {
  886.                     
  887.                         case 'b':                                                                                        //parameter is long value for boolean. output F for zero, otherwise T
  888.                             paramVal = va_arg(paramPtr, long);                                //get the boolean value
  889.                             status = RDBufferByte(  paramVal ? 'T' : 'F', hRDMap, params->rdFlags);                // buffer 'T' or 'F' based on value.
  890.                             break;
  891.                                                 
  892.                         case 'd':                                                                                        //parameter is an integer.
  893.                         
  894.                             paramVal = va_arg(paramPtr, long);                                //get the integer.
  895.                             NumToString(paramVal, (unsigned char *) tempString);                                //convert it to a string.
  896.                             
  897.                             status  = RDBufferData(&(tempString[1]), StrLength((unsigned char*)tempString),
  898.                                                                 hRDMap, params->rdFlags);    //Blow it out.
  899.                             break;
  900.                         
  901.                         case 'f':                                                            //parameter is a fixed point number.
  902.                         
  903.                             paramVal = (long) va_arg(paramPtr, Fixed);                                            //get the fixed number.
  904.                             status = RDBufferFixedVal(paramVal, hRDMap, params->rdFlags);        //buffer it.
  905.                             break;
  906.                             
  907.                         case 'p':                                                            //parameter is a gx graphics point.
  908.                         
  909.                             paramVal = (long) va_arg(paramPtr, gxPoint*);
  910.                             
  911.                             //Output the X value.
  912.                             status = RDBufferFixedVal(((gxPoint*)paramVal)->x, hRDMap, params->rdFlags);
  913.                             nrequire (status, failed_buffering2); 
  914.                             
  915.                             //output a the seperator between x and y
  916.                             status = RDBufferByte((*hRDMap)->xySep, hRDMap, params->rdFlags);
  917.                             nrequire (status, failed_buffering3); 
  918.                             
  919.                             //Output the Y value.
  920.                             status = RDBufferFixedVal(((gxPoint*)paramVal)->y, hRDMap, params->rdFlags);
  921.                                         
  922.                             break;
  923.                             
  924.                         case 's':                                                                        //parameter is a string.
  925.                         
  926.                             beginBlock = va_arg(paramPtr, char*);    //get the pointer.
  927.                             paramVal = va_arg(paramPtr, long);                        //get the length.
  928.                             
  929.                             if (mustSubstitute) {                                                    //do character substituion if needed.
  930.                             
  931.                                 status = RDBufferSubstituteString(beginBlock, paramVal, hRDMap, params->rdFlags);
  932.                             
  933.                             } else {                                                                            //just dump the string normally.
  934.                             
  935.                                 status = RDBufferData(beginBlock, paramVal, hRDMap, params->rdFlags);
  936.                                 
  937.                             }//end if
  938.                             
  939.                             break;
  940.                         
  941.                         case 'q':                                                                        // parameter is a pascal string.
  942.                         
  943.                             beginBlock = va_arg(paramPtr, char*);                // Get pointer to the string.
  944.                             paramVal = (unsigned char)(*beginBlock++);    // Get the length, skip to first byte.
  945.                             
  946.                             if (mustSubstitute) {                                                    //do character substituion if needed.
  947.                             
  948.                                 status = RDBufferSubstituteString(beginBlock, paramVal, hRDMap, params->rdFlags);
  949.                             
  950.                             } else {                                                                            //just dump the string normally.
  951.                             
  952.                                 status = RDBufferData(beginBlock, paramVal, hRDMap, params->rdFlags);
  953.                                 
  954.                             }//end if
  955.                         
  956.                             break;
  957.                             
  958.                         case 'h':                                                                        //parameter is binary data, convert to hex.
  959.                         
  960.                             beginBlock = va_arg(paramPtr, char*);                    //get the pointer.
  961.                             paramVal = va_arg(paramPtr, long);                        //get the length.
  962.                             
  963.                             nrequire(status = RDFlushBuffer(hRDMap), failed_buffering4);  // flush previous stuff.
  964.                             status = (*hRDMap)->psDevice->BufferData(beginBlock, paramVal, params->rdFlags | eRDMakeHex);        
  965.                                         
  966.                             break;
  967.     
  968.                             
  969.                         default:                //If none of the substitution characters followed the %, send the '%'
  970.                                                         //  And start parsing again at the character right after it.
  971.                         
  972.                             inString -= 2;                            //Move back to the % character.
  973.                             
  974.                             status = RDBufferByte(*inString++, hRDMap, params->rdFlags);        //Blow it out.
  975.                     
  976.                     }//end switch
  977.     
  978.                 }//end if
  979.             
  980.             }//end if
  981.                         
  982.             nrequire(status, failed_buffering5);
  983.             
  984.         } //end while 
  985.         
  986.         if (!(params->rdFlags & eRDNoAutoFlush))
  987.             status = RDFlushBuffer(hRDMap);
  988.  
  989.         ncheck(status);
  990.  
  991. failed_buffering1:
  992. failed_buffering2:
  993. failed_buffering3:
  994. failed_buffering4:
  995. failed_buffering5:
  996.  
  997.         va_end(paramPtr);
  998.  
  999.  
  1000. failed_GetInd:
  1001.  
  1002.         HSetState(hResource, flags);
  1003.  
  1004. failed_GetRes:
  1005.         
  1006.         return(status);
  1007.     
  1008.     }//RDResPrintf
  1009.  
  1010. //<FF>
  1011.  
  1012.  
  1013. /*********************************
  1014.     Routine: RDSetSubstitutions
  1015.     
  1016.     This routine is called to set the string substitution
  1017.     for RDResPrintf to use for %s parameters.
  1018.     
  1019.     rdMap:            The Client's map.
  1020.     nSubs:            How many substitutions we're specifying.
  1021.     ...                    The list of substitutions.  char, spstring, char, pstring...
  1022.     
  1023. ************************************/
  1024. OSErr RDSetSubstitutions(TRDMapHdl rdMap, long nSubs, ...)
  1025.     {
  1026.         register short    i;                                        //loop counter.
  1027.         OSErr                        status = noErr;
  1028.         va_list                    paramPtr;                            //Pointer to next paramter.
  1029.         long                        paramVal;                            //value of the parameter.
  1030.         long                        memSize;                            //Memory size to allocate.
  1031.         UInt8                        subLen;                                //length of substitution string.
  1032.         Handle                    hSubs;
  1033.         Ptr                            pSubs;
  1034.         Ptr                            pSubsBits;
  1035.         UInt8                        *pMask;
  1036.         
  1037.                 
  1038.         /** Clear out the substitution bit mask **/
  1039.         pMask = (*rdMap)->subsBits;
  1040.         memset(pMask, 0, 32);
  1041.     
  1042.         /*****
  1043.                 Figure out how much memory to allocate for the substitutions
  1044.                 by traversing the parameter list.
  1045.         ******/
  1046.         memSize = 0;
  1047.         va_start(paramPtr, nSubs);
  1048.         for (i = nSubs-1; i >=0; --i) {
  1049.         
  1050.             paramVal = va_arg(paramPtr, long);            //skip the byte to substitute
  1051.             paramVal = (long) va_arg(paramPtr, UInt8*);            //get the length of the substitution string.
  1052.             
  1053.             memSize += 2 + *(UInt8*)paramVal;                //add size of string, 1 for the byte, 1 for length byte.
  1054.             
  1055.         }//end for
  1056.         
  1057.         va_end(paramPtr);
  1058.  
  1059.         /** Now try to allocate the memory for the new substitution array. **/
  1060.         
  1061.         hSubs = (*rdMap)->hCharSubstitute;
  1062.         
  1063.         if (hSubs == nil) {        
  1064.         
  1065.             status = PrNewHandle(&hSubs, memSize);
  1066.             (*rdMap)->hCharSubstitute = hSubs;
  1067.             
  1068.         } else {
  1069.         
  1070.             status = PrSetHandleSize( hSubs, memSize);
  1071.             
  1072.         }//end if
  1073.         nrequire (status, failed_AllocNewSubs);
  1074.                     
  1075.         pSubs = *hSubs;
  1076.     
  1077.         /* Now retraverse the parameter list and load the handle with the substitutions */
  1078.         va_start(paramPtr, nSubs);
  1079.         
  1080.         pSubsBits = (char *) (*rdMap)->subsBits;
  1081.         
  1082.         for (i = nSubs-1; i >= 0; --i) {
  1083.         
  1084.             paramVal = (long) va_arg(paramPtr, char*);        //get the byte to substitute
  1085.             *pSubs++ = (char)paramVal;                                            //stick it in the array.
  1086.             
  1087.             /** Set the bit in the array of substitution characters **/
  1088.  
  1089.             BITSET(pSubsBits, (UInt8)paramVal);
  1090.             
  1091.             
  1092.             paramVal = (long) va_arg(paramPtr, char*);                    //get the pstring to substitute for
  1093.             subLen = *(UInt8*)paramVal;                                                    // get the length of the pstring.
  1094.  
  1095.             BlockMoveData((char*)paramVal, pSubs, subLen + 1);    //stick it in the array.
  1096.             
  1097.             pSubs += (subLen + 1);                                                            //move to next position in array.
  1098.         
  1099.         }//end for
  1100.         
  1101.         va_end(paramPtr);
  1102.         
  1103.         (*rdMap)->nSubs = nSubs;
  1104.     
  1105.     
  1106. failed_AllocNewSubs:
  1107.  
  1108.         return(status);
  1109.                 
  1110.     }//RDSetSubstitutions
  1111.  
  1112.  
  1113. //<FF>
  1114. /****************************************************
  1115.     Funciton: RDSetXYSep
  1116.     
  1117.     Set the character that will be used to seperate the x and y values
  1118.     in a %p formatted point.
  1119.     
  1120.     rdMap:        The client's map.
  1121.     theChar:    The character to use as the seperator.
  1122.     
  1123. ****************************************************/
  1124.  
  1125. OSErr RDSetXYSep(TRDMapHdl rdMap, char theChar)
  1126.     {
  1127.         check(rdMap);
  1128.         
  1129.         (*rdMap)->xySep = theChar;
  1130.         return noErr;
  1131.         
  1132.     }//RDSetXYSep
  1133.     
  1134. //<FF>
  1135. /****************************************************
  1136.     Funciton: RDInvalResCache
  1137.     
  1138.     Invalidates the cache used by RDResPrintf.
  1139.     
  1140.     rdMap:        The client's map.
  1141.     
  1142. ****************************************************/
  1143. OSErr RDInvalResCache(TRDMapHdl rdMap)
  1144.     {
  1145.         register TRDMapPtr pMap = *(TRDMapHdl)rdMap;
  1146.         
  1147.         pMap->hLastResource = nil;
  1148.         pMap->lastResID = 0;
  1149.         pMap->lastResType = '????';
  1150.         pMap->lastResRef = 0;
  1151.         return noErr;
  1152.         
  1153.     }//RDInvalResCache
  1154.